package com.yaowk.service.system.service.impl;

import com.yaowk.api.common.StatusDict;
import com.yaowk.api.system.Config;
import com.yaowk.api.system.model.Menu;
import com.yaowk.api.system.service.IMenuService;
import com.yaowk.service.common.BaseRepository;
import com.yaowk.service.common.BaseServiceImpl;
import com.yaowk.service.system.dao.MenuRepository;
import com.yaowk.service.system.dao.RoleRepository;
import com.yaowk.service.system.dao.UserRepository;
import com.yaowk.service.system.entity.SysMenu;
import com.yaowk.service.system.entity.SysPermission;
import com.yaowk.service.system.entity.SysRole;
import com.yaowk.service.system.entity.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.transaction.Transactional;
import java.util.*;

@Service
public class MenuServiceImpl extends BaseServiceImpl<Menu, SysMenu, Integer> implements IMenuService {

    @Autowired
    private MenuRepository dao;
    @Autowired
    private RoleRepository roleDao;
    @Autowired
    private UserRepository userDao;

    @Override
    protected BaseRepository<SysMenu, Integer> getDao() {
        return dao;
    }

    @Override
    protected SysMenu model2Entity(Menu model) {
        SysMenu sysMenu = null;
        if (!ObjectUtils.isEmpty(model)) {
            sysMenu = new SysMenu();
            sysMenu.setCreateTime(model.getCreateTime());
            sysMenu.setDescription(model.getDescription());
            sysMenu.setId(model.getId());
            sysMenu.setName(model.getName());
            sysMenu.setParentId(model.getParentId());
            sysMenu.setSort(model.getSort());
            sysMenu.setStatus(model.getStatus());
            sysMenu.setType(model.getType());
            sysMenu.setUrl(model.getUrl());
        }
        return sysMenu;
    }

    @Override
    protected Menu entity2model(SysMenu entity) {
        Menu menu = null;
        if (!ObjectUtils.isEmpty(entity)) {
            menu = new Menu();
            menu.setCreateTime(entity.getCreateTime());
            menu.setDescription(entity.getDescription());
            menu.setId(entity.getId());
            menu.setName(entity.getName());
            menu.setParentId(entity.getParentId());
            menu.setSort(entity.getSort());
            menu.setStatus(entity.getStatus());
            menu.setType(entity.getType());
            menu.setUrl(entity.getUrl());
        }
        return menu;
    }

    @Override
    public List<Menu> findMenusByRoleId(Integer roleId) {
        SysRole sysRole = roleDao.findOne(roleId);
        return entity2Model(sysRole.getMenus());
    }

    @Override
    @Transactional
    public Menu save(Menu model) {
        if (ObjectUtils.isEmpty(model.getId())) {
            model = simpleSave(model);
        } else {
            SysMenu sysMenu = dao.findOne(model.getId());
            if (isNotEmpty(model.getStatus()))
                sysMenu.setStatus(model.getStatus());
            if (isNotEmpty(model.getName()))
                sysMenu.setName(model.getName());
            if (isNotEmpty(model.getDescription()))
                sysMenu.setDescription(model.getDescription());
            if (isNotEmpty(model.getSort()))
                sysMenu.setSort(model.getSort());
            if (isNotEmpty(model.getType()))
                sysMenu.setType(model.getType());
            if (isNotEmpty(model.getUrl()))
                sysMenu.setUrl(model.getUrl());
            model = entity2model(dao.save(sysMenu));
        }
        return model;
    }

    @Override
    @Transactional
    public void permissionEdit(Integer menuId, List<Integer> permissionIds) {
        SysMenu sysMenu = dao.findOne(menuId);
        Set<SysPermission> sysPermissions = new HashSet<>();
        sysMenu.setPermissions(sysPermissions);
        if (!CollectionUtils.isEmpty(permissionIds))
            for (Integer id : permissionIds) {
                SysPermission sysPermission = new SysPermission();
                sysPermission.setId(id);
                sysPermissions.add(sysPermission);
            }
        dao.save(sysMenu);
    }

    @Override
    public List<String> findAliases(Menu menu) {
        SysMenu sysMenu = dao.findOne(Example.of(model2Entity(menu)));
        List<String> userIds = new ArrayList<>();
        if (isNotEmpty(sysMenu)) {
            Set<SysRole> sysRoles = sysMenu.getRoles();
            for (SysRole sysRole : sysRoles) {
                Set<SysUser> sysUsers = sysRole.getUsers();
                for (SysUser sysUser : sysUsers) {
                    userIds.add(sysUser.getUsername());
                }
            }
        }
        return userIds;
    }

    @Override
    @Transactional
    public List<Menu> findMenusByUserId(Integer userId) {
        SysUser user = userDao.findOne(userId);
        Set<SysRole> roles = user.getRoles();
        Collection<SysMenu> menus = new HashSet<>();
        for (SysRole role : roles) {
            Set<SysMenu> menuSet = role.getMenus();
            for (SysMenu menu : menuSet) {
                if (menu.getStatus().equals(StatusDict.NORMAL)) {
                    menus.add(menu);
                }
            }
        }
        return entity2Model(menus);
    }

    @Override
    public List<Menu> findMenusConfigByUserId(Integer userId) {
        SysUser user = userDao.findOne(userId);
        Set<SysRole> roles = user.getRoles();
        Collection<SysMenu> menus = new HashSet<>();
        for (SysRole role : roles) {
            if (role.getStatus().equals(StatusDict.NORMAL)) {
                Set<SysMenu> menuSet = role.getMenus();
                for (SysMenu menu : menuSet) {
                    if (menu.getStatus().equals(StatusDict.NORMAL)) {
                        addMenu(menu, menus);
                    }
                }
            }
        }
        return entity2Model(menus);
    }

    @Override
    @Transactional
    public Menu simpleSave(Menu model) {
        model = super.simpleSave(model);

        // 保存菜单之后还需要配置给系统管理员角色
        SysRole sysRole = roleDao.findOne(Config.SYSTEM_MANAGER_ROLE_ID);
        Set<SysMenu> menus = sysRole.getMenus();
        SysMenu sysMenu = new SysMenu();
        sysMenu.setId(model.getId());
        menus.add(sysMenu);
        roleDao.save(sysRole);
        return model;
    }

    @Override
    public void deleteById(Integer integer) {
        SysMenu sysMenu = dao.findOne(integer);
        for (SysRole sysRole : sysMenu.getRoles()) {
            sysRole.getMenus().remove(sysMenu);
            roleDao.save(sysRole);
        }
        super.deleteById(integer);
    }

    private void addMenu(SysMenu menu, Collection<SysMenu> menuSet) {
        menuSet.add(menu);
        if (!ObjectUtils.isEmpty(menu.getParentId())) {
            SysMenu parent = dao.findOne(menu.getParentId());
            addMenu(parent, menuSet);
        }
    }
}
